package cgo

/*
 #include "cgo.h"
*/
import "C"
import (
	"reflect"
	"sync"
	"sync/atomic"
	"unsafe"
)

var funcMap sync.Map
var funcOrder atomic.Int64

type CFunction func(args []unsafe.Pointer) uintptr

func BindFunction(f CFunction) int64 {
	id := funcOrder.Add(1)
	funcMap.Store(id, f)
	return id
}

func UnbindFunction(id int64) {
	funcMap.Delete(id)
}

//export cgoGlobalFunction
func cgoGlobalFunction(id int64, argLen int64, pointer unsafe.Pointer) int64 {
	f, ok := funcMap.Load(id)
	if !ok {
		return 0
	}
	sourceArgs := make([]unsafe.Pointer, argLen)
	uintptrArray := (*[1 << 31]unsafe.Pointer)(pointer)[0:argLen]
	copy(sourceArgs, uintptrArray)
	retRvs := reflect.ValueOf(f).Call([]reflect.Value{reflect.ValueOf(sourceArgs)})
	if len(retRvs) > 1 {
		return 0
	}
	if len(retRvs) == 0 {
		return 0
	}
	value := retRvs[0]
	return value.Interface().(int64)
}

func init() {
	C.initExportedFunction()
}
